跳到主要内容

Go 的字符操作

Golang 中似乎没有 StringBuffer 这种东西,今天刷题遇到需要操作字符串,如果直接使用 += 这种大力出奇迹肯定不行,所以看下别人是怎么用 Golang 进行字符添加的,发现用到了 rune 类型,遂好奇这是什么类型?

// 反转字符串
func reverseString(s string) string {
runes := []rune(s)
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
return string(runes)
}

Golang 中的字符

字符串中的每一个元素叫做 “字符”,在遍历或者单个获取字符串元素时可以获得字符。

Go 语言的字符有以下两种:

  • 一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符。
  • 另一种是 rune 类型,代表一个 UTF-8 字符,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。

byte 类型是 uint8 的别名,对于只占用 1 个字节的传统 ASCII 编码的字符来说,完全没有问题,例如 var ch byte = 'A',字符使用单引号括起来。

rune 类型等价于 int32 类型,它用来区分字符值和整数值

计算机在底层处理的都是零和一的数字,那么字符串也不另外。string 字符串在转换成 byte 之后其实都是一个数值,我们知道常规的英文字符是 ascii 码是通过一个字节( 2^8 其实还有一位是不用的 )来存储,中国文字、日本文字常用文字就有 4000+,通过 2^8 肯定表达不了,所有可以通过 unicode 来存储,占用 2 个字节。

所以对于那些存储了汉字类型的数据应该转成 rune 类型串

runes := []rune(s)

string() 的坑

string 函数与 strconv.Itoa 函数的区别

strconv.Itoa 函数的参数是一个整型数字,它可以 将数字转换成对应的字符串类型的数字

package main

import (
"fmt"
"strconv"
)

func main() {
string_number := 97
result := strconv.Itoa(string_number)

fmt.Println(result)
fmt.Printf("%T\n", result)
}

运行结果:

97
string

string() 则是把整型数字转换成 ASCII 码相同字符

package main

import (
"fmt"
)

func main() {
string_number := 97
result := string(string_number)

fmt.Println(result)
fmt.Printf("%T\n", result)
}

运行结果:

a
string

因为 ASCII 码值为 97 对应的字符是 a,所以 string(97) 的结果是 a

strconv 标准库

strconv 是 Golang 的一个标准包,实现了基本数据类型和其字符串表示的相互转换。

字符串与布尔类型

func ParseBool(str string) (value bool, err error)

返回布尔类型,可接受 1、0、t、f、T、F、true、false、True、False、TRUE、FALSE;否则返回错误。

func FormatBool(b bool) string

FormatBool 根据 b 的值返回 “true” 或 “false” 的字符串

字符串与整数类型

返回字符串表示的 64 位整数值,接受正负号。

func ParseInt(s string, base int, bitSize int) (i int64, err error)

base 指定进制(2 到 36),如果 base 为0,则会从字符串前置判断,“0x" 是 16 进制,“0" 是 8 进制,否则是 10 进制;

bitSize 指定结果必须能无溢出赋值的整数类型,0、8、16、32、64 分别代表 int、int8、int16、int32、int64;返回的 err 是 *NumErr 类型的,如果语法有误,err.Error = ErrSyntax;如果结果超出类型范围 err.Error = ErrRange

与 ParseInt 使用相同接受无符号整数类型。

// Atoi 是 ParseInt(s, 10, 0) 的简写。
func Atoi(s string) (int, error)

FormatInt 返回 i 的 base 进制的字符串表示,base 在 2 到 36 之间。结果中使用 ‘a’ 到 ‘z’ 表示大于 10 的数值

func FormatInt(i int64, base int) string

函数同 FormatInt 功能相同针对无符号整数类型。

// Itoa 等同于 FormatInt(int64(i), 10)
func Itoa(i int) string

字符串转为浮点数

返回浮点数数值。指定 bitSize 大小设置精度:

  • 32 表示 float3;
  • 64 表示float64。

当 bitSize = 32 时,返回结果类型为 float64 时,也可以无损的转换为 float32。

func ParseFloat(s string, bitSize int) (float64, error)

可接受十进制和十六进制的浮点数字符串转换。如果 s 符合规则且接近一个有效的浮点数, ParseFloat 将返回使用 IEEE754 标准四舍五入的最近浮点数。如果解析十六进制浮点数时,只有在十六进制表示的数超过限定的位数时,就会进行舍入。

字符拼接 Builder

使用 strings.Builder 替换 + 进行字符串拼接,将有效地降低内存消耗。

// strings.Builder的0值可以直接使用
var builder strings.Builder

// 向builder中写入字符/字符串
builder.Write([]byte("Hello"))
builder.WriteByte(' ')
builder.WriteString("World")

// String() 方法获得拼接的字符串
builder.String() // "Hello World"

String 数组连接

var columns []string
// ...
desc := strings.Join(columns, ",")

Sprintf 格式化输出字符

这个是 fmt 包提供的一个格式字符串的包

s := fmt.Sprintf("%.4f", math.Pi) // s == "3.1416"

下面介绍下 常用的 strings 包

Search 前缀\后缀\索引

| Expression                           | Result | Note                             |
| ------------------------------------ | ------ | -------------------------------- |
| strings.Contains("Japan", "abc") | false | Is abc in Japan? |
| strings.ContainsAny("Japan", "abc") | true | Is a, b or c in Japan? |
| strings.Count("Banana", "ana") | 1 | Non-overlapping instances of ana |
| strings.HasPrefix("Japan", "Ja") | true | Does Japan start with Ja? |
| strings.HasSuffix("Japan", "pan") | true | Does Japan end with pan? |
| strings.Index("Japan", "abc") | -1 | Index of first abc |
| strings.IndexAny("Japan", "abc") | 1 | a, b or c |
| strings.LastIndex("Japan", "abc") | -1 | Index of last abc |
| strings.LastIndexAny("Japan", "abc") | 3 | a, b or c |

Replace 大小字母\小写字母\截断

// Replace first two “o” with “.” Use -1 to replace all
strings.Replace("foo", "o", ".", 2) // f..

// Apply function to each character
f := func(r rune) rune {
return r + 1
}
strings.Map(f, "ab") // bc


strings.ToUpper("Japan") // JAPAN Uppercase
strings.ToLower("Japan") // japan Lowercase
strings.Title("ja pan") // Ja Pan Initial letters to uppercase

// foo Strip leading and trailing white space
strings.TrimSpace(" foo\n")


strings.Trim("foo", "fo") // Strip leading and trailing f:s and o:s
strings.TrimLeft("foo", "f") // oo only leading
strings.TrimRight("foo", "o") // f only trailing


strings.TrimPrefix("foo", "fo") // o
strings.TrimSuffix("foo", "o") // fo

Split 切割字符串

| Expression                     | Result     | Note               |
| ------------------------------ | ---------- | ------------------ |
| strings.Fields(" a\t b\n") | ["a" "b"] | Remove white space |
| strings.Split("a,b", ",") | ["a" "b"] | Remove separator |
| strings.SplitAfter("a,b", ",") | ["a," "b"] | Keep separator |

组合和重复

| Expression                            | Result | Note             |
| ------------------------------------- | ------ | ---------------- |
| strings.Join([]string{"a", "b"}, ":") | a:b | Add separator |
| strings.Repeat("da", 2) | dada | 2 copies of “da” |